home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / Xconq 7.0d16 / Xconq 7.0d16 src / mac / macdesign.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-04  |  32.6 KB  |  1,066 lines  |  [TEXT/KAHL]

  1. /* Copyright (c) 1992, 1993  Stanley T. Shebs. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. /* Mac designer handling. */
  6.  
  7. #include "conq.h"
  8. #include "mac.h"
  9.  
  10. /* (should be declared in world.h) */
  11.  
  12. extern int mintemp, maxtemp, tempscanvary, tempscanvaryinlayer;
  13. extern int minwindforce, maxwindforce, windscanvary, windscanvaryinlayer;
  14.  
  15. extern int anyclouds;
  16.  
  17. extern int anymaterialsinterrain;
  18.  
  19. #ifdef DESIGNERS
  20.  
  21. #define numtooltypes 12
  22.  
  23. extern MenuHandle featuremenu;
  24.  
  25. WindowPtr designwin = nil;
  26.  
  27. ControlHandle ttypepopup = nil;
  28. ControlHandle utypepopup = nil;
  29. ControlHandle mtypepopup = nil;
  30. ControlHandle sidepopup = nil;
  31. ControlHandle newfeaturebutton = nil;
  32. ControlHandle featurerenamebutton = nil;
  33. ControlHandle featurepopup = nil;
  34.  
  35. CursHandle paintcursors[numtooltypes];
  36. CursHandle bordpaintor;
  37. CursHandle connpaintor;
  38. CursHandle coatpaintor;
  39.  
  40. /* This is the width and height of each design tool's entry. */
  41.  
  42. int dtoolw = 120;
  43. int dtoolh = 36;
  44.  
  45. /* The type of designer tool currently in use. */
  46.  
  47. enum tooltype tooltype = notool;
  48.  
  49. /* All the state of the designer palette. */
  50.  
  51. short curbrushradius = 0;
  52. short curttype = 0;
  53. short curbgttype = 0;
  54. short curdepth = 1;
  55. short curutype = 0;
  56. short cursidenumber = 0;
  57. short curmtype = 0;
  58. short curmamount = 0;
  59. short curfid = 0;
  60. Feature *curfeature = NULL;
  61. char *curfeaturetypename;
  62. char *curfeaturename;
  63. short curelevation = 0;
  64. short curtemperature = 0;
  65. short curcloudtype = 0;
  66. short curcloudbottom = 0;
  67. short curcloudheight = 0;
  68. short curwinddir = 0;
  69. short curwindforce = 0;
  70.  
  71. /* These are globals used in drag painting. */
  72.  
  73. short painttype;
  74. short paintpeop;
  75. short paintfid;
  76.  
  77. short enabledtooltype[20];
  78.  
  79. enable_designing(forsure)
  80. int forsure;
  81. {
  82.     extern int compromised;
  83.  
  84.     if (dside == NULL || dside->designer) return;
  85.     if (!forsure && !compromised) {
  86.         switch (CautionAlert(aConfirmDesign, nil)) {
  87.             case aiConfirmDesignOK:
  88.                 break;
  89.             case aiConfirmDesignCancel:
  90.                 return;
  91.         }
  92.     }
  93.     /* Actually change designer status, this will call back to alter all displays. */
  94.     become_designer(dside);
  95.     /* Create and add the designer's palette. */
  96.     if (designwin == nil) {
  97.         create_design_window();
  98.     }
  99.     if (designwin != nil) {
  100.         position_design_window();
  101.         ShowWindow(designwin);
  102. /*        SelectWindow(designwin); */
  103.     }
  104.     /* Recache visibility flags. */
  105.     calc_vision();
  106. }
  107.  
  108. disable_designing()
  109. {
  110.     if (dside == NULL || !dside->designer) return;
  111.     /* Hide (but don't destroy) the designer's palette. */
  112.     if (designwin != nil) {
  113.         HideWindow(designwin);
  114.     }
  115.     /* Actually change designer status, this will call back to alter all displays. */
  116.     become_nondesigner(dside);
  117.     /* Recache visibility flags. */
  118.     calc_vision();
  119. }
  120.  
  121. /* Each type of design tool has a distinct cursor. */
  122.  
  123. init_design_cursors()
  124. {
  125.     paintcursors[terraintool] = GetCursor(cCell);
  126.     bordpaintor = GetCursor(cBord);
  127.     connpaintor = GetCursor(cConn);
  128.     coatpaintor = GetCursor(cCoat);
  129.     paintcursors[unittool] = GetCursor(cUnit);
  130.     paintcursors[peopletool] = GetCursor(cPeople);
  131.     paintcursors[materialtool] = GetCursor(cMaterial);
  132.     paintcursors[featuretool] = GetCursor(cFeature);
  133.     paintcursors[elevationtool] = GetCursor(cElevation);
  134.     paintcursors[temperaturetool] = GetCursor(cTemperature);
  135.     paintcursors[cloudstool] = GetCursor(cClouds);
  136.     paintcursors[windstool] = GetCursor(cWinds);
  137. }
  138.  
  139. /* Adjust the cursor to reflect the current designer tool. */
  140.  
  141. CursPtr
  142. adjust_designer_cursor(mouse, region)
  143. Point mouse;
  144. RgnHandle region;
  145. {
  146.     if (tooltype == terraintool && !t_is_cell(curttype)) {
  147.         switch (t_subtype(curttype)) {
  148.             case bordersubtype:
  149.                 return *bordpaintor;
  150.             case connectionsubtype:
  151.                 return *connpaintor;
  152.             case coatingsubtype:
  153.                 return *coatpaintor;
  154.             default:
  155.                 terrain_subtype_warning("cursor adjust", curttype);
  156.                 return &QD(arrow);
  157.         }
  158.     }
  159.     return *(paintcursors[tooltype]);
  160. }
  161.  
  162. /* Create the designer tool window. */
  163.  
  164. create_design_window()
  165. {
  166.     if (hasColorQD) {
  167.         designwin = GetNewCWindow(wDesign, NULL, (WindowPtr) -1L);
  168.     } else {
  169.         designwin = GetNewWindow(wDesign, NULL, (WindowPtr) -1L);
  170.     }
  171.     add_window_menu_item("Design", designwin);  /* until this becomes a windoid */
  172.     /* Make the current side be the one with the display. */
  173.     cursidenumber = side_number(dside);
  174.     build_terrain_type_menu();
  175.     build_unit_type_menu();
  176.     build_side_menu();
  177.     build_material_type_menu();
  178.     build_feature_menu();
  179.     ttypepopup = GetNewControl(mTerrainTypes, designwin);
  180.     utypepopup = GetNewControl(mUnitTypes, designwin);
  181.     sidepopup = GetNewControl(mSides, designwin);
  182.     mtypepopup = GetNewControl(mMaterialTypes, designwin);
  183.     featurepopup = GetNewControl(mFeatures, designwin);
  184.     newfeaturebutton = GetNewControl(cNewFeatureButton, designwin);
  185.     featurerenamebutton = GetNewControl(cFeatureRenameButton, designwin);
  186.     SizeWindow(designwin, 2 * dtoolw - 1, (numtooltypes / 2) * dtoolh - 1, 1);
  187.     position_design_window();
  188.     init_design_cursors();
  189.     enabledtooltype[notool] = TRUE;
  190.     enabledtooltype[terraintool] = TRUE;
  191.     enabledtooltype[unittool] = TRUE;
  192.     enabledtooltype[peopletool] = TRUE;
  193.     enabledtooltype[featuretool] = TRUE;
  194.     enabledtooltype[brushsizetool] = TRUE;
  195.     enabledtooltype[materialtool] = anymaterialsinterrain;
  196.     enabledtooltype[elevationtool] = !world_is_flat();
  197.     enabledtooltype[temperaturetool] = tempscanvary;
  198.     enabledtooltype[cloudstool] = anyclouds;
  199.     enabledtooltype[windstool] = windscanvary;
  200.     ShowWindow(designwin);
  201. }
  202.  
  203. /* Try to put the palette alongside the frontmost window. */
  204.  
  205. position_design_window()
  206. {
  207.     Point pt;
  208.     WindowPtr win;
  209.     GrafPtr oldport;
  210.  
  211.     /* (should fix all this) */
  212.     if ((win = FrontWindow()) != nil) {
  213.         GetPort(&oldport);
  214.         SetPort(win);
  215.         SetPt(&pt, win->portRect.right + 3, win->portRect.top);
  216.         LocalToGlobal(&pt);
  217.         SetPort(oldport);
  218.     } else {
  219.         SetPt(&pt, 500, 50);
  220.     }
  221.     /* (should make sure is not off the edge of the screen) */
  222.     if (pt.h + 2 * dtoolw > 640 /* is off screen entirely */) {
  223.         SetPt(&pt, 640 - 2 * dtoolw - 2, 50);
  224.     }
  225.     MoveWindow(designwin, pt.h, pt.v, TRUE);
  226. }
  227.  
  228. draw_design_window()
  229. {
  230.     int i;
  231.     GrafPtr oldport;
  232.  
  233.     if (!active_display(dside) || designwin == nil) return;
  234.     GetPort(&oldport);
  235.     SetPort(designwin);
  236.     /* Draw each tool's palette item. */
  237.     for (i = 0; i < numtooltypes; ++i) {
  238.         draw_design_window_tool(i);
  239.     }
  240.     DrawControls(designwin);
  241.     SetPort(oldport);
  242. }
  243.  
  244. draw_design_window_tool(tool)
  245. enum tooltype tool;
  246. {
  247.     int enabled = TRUE, paintable = TRUE;
  248.     char *toolname = NULL, *auxtoolname = NULL;
  249.     Rect tmprect, imagerect;
  250.     char imbuf[BUFSIZE];
  251.     Str255 tmpstr;
  252.  
  253.     SetRect(&tmprect, 0, 0, dtoolw, dtoolh);
  254.     OffsetRect(&tmprect, (tool / (numtooltypes/2)) * dtoolw, (tool % (numtooltypes/2)) * dtoolh);
  255.     EraseRect(&tmprect);
  256.     /* Confine the image to a square subrect on the left side of the window. */
  257.     imagerect = tmprect;
  258.     imagerect.right = imagerect.left + dtoolh;
  259.     imbuf[0] = '\0';
  260.     switch (tool) {
  261.         case notool:
  262.             toolname = "Normal";
  263.             break;
  264.         case terraintool:
  265.             toolname = t_type_name(curttype);
  266.             InsetRect(&imagerect, (dtoolh - hws[4]) / 2, (dtoolh - hhs[4]) / 2);
  267.             /* Only do bg terrain type if painting cell terrain. */
  268.             if (t_is_cell(curttype)) {
  269.                 auxtoolname = t_type_name(curbgttype);
  270.                 /* bg type is always cell subtype. */
  271.                 OffsetRect(&imagerect, 3, 3);
  272.                 draw_terrain_sample(imagerect, curbgttype);
  273.                 OffsetRect(&imagerect, -6, -6);
  274.             }
  275.             draw_terrain_sample(imagerect, curttype);
  276.             break;
  277.         case unittool:
  278.             toolname = u_type_name(curutype);
  279.             InsetRect(&imagerect, (dtoolh - 32) / 2, (dtoolh - 32) / 2);
  280.              draw_unit_image(designwin, imagerect.left, imagerect.top, 32, 32,
  281.                              curutype, cursidenumber, 0);
  282.             /* Gray out the unit if not allowed for the current side. */
  283.             paintable = type_allowed_on_side(curutype, side_n(cursidenumber));
  284.             break;
  285.         case peopletool:
  286.             shortest_side_title(side_n(cursidenumber), spbuf);
  287.             toolname = spbuf;
  288.             InsetRect(&imagerect, (dtoolh - 16) / 2, (dtoolh - 16) / 2);
  289.             draw_side_emblem(designwin, imagerect.left, imagerect.top, 16, 16,
  290.                              cursidenumber);
  291.             break;
  292.         case featuretool:
  293.             if (enabledtooltype[featuretool]) {
  294.                 if (curfeature == NULL) {
  295.                     curfeature = (Feature *) find_feature(curfid);
  296.                 }
  297.                 if (curfeature != NULL) {
  298.                     toolname = curfeature->typename;
  299.                     auxtoolname = curfeature->name;
  300.                 }
  301.                 sprintf(imbuf, "#%d", curfid);
  302.             } else {
  303.                 toolname = "Feature";
  304.                 enabled = FALSE;
  305.             }
  306.             break;
  307.         case brushsizetool:
  308.             OffsetRect(&imagerect, dtoolh/2 - curbrushradius, dtoolh/2 - curbrushradius);
  309.             imagerect.right = imagerect.left + curbrushradius + 1;
  310.             imagerect.bottom = imagerect.top + curbrushradius + 1;
  311.             FillOval(&imagerect, QD(black));
  312.             if (curbrushradius > 0) {
  313.                 sprintf(imbuf, "%d", curbrushradius);
  314.             }
  315.             toolname = "Brush";
  316.             break;
  317.         case materialtool:
  318.             if (enabledtooltype[materialtool]) {
  319.                 toolname = m_type_name(curmtype);
  320.                 sprintf(imbuf, "%d", curmamount);
  321.             } else {
  322.                 toolname = "Material";
  323.                 enabled = FALSE;
  324.             }
  325.             break;
  326.         case elevationtool:
  327.             if (enabledtooltype[elevationtool]) {
  328.                 sprintf(spbuf, "Elev %d", curelevation);
  329.                 toolname = spbuf;
  330.             } else {
  331.                 toolname = "Elevation";
  332.                 enabled = FALSE;
  333.             }
  334.             break;
  335.         case temperaturetool:
  336.             if (enabledtooltype[temperaturetool]) {
  337.                 sprintf(spbuf, "Temp %d°", curtemperature);
  338.                 toolname = spbuf;
  339.             } else {
  340.                 toolname = "Temperature";
  341.                 enabled = FALSE;
  342.             }
  343.             break;
  344.         case cloudstool:
  345.             if (enabledtooltype[cloudstool]) {
  346.                 /* Black is not ideal here... */
  347.                 FillRect(&imagerect, QD(black));
  348.                 if (curcloudtype > 0) {
  349.                     InsetRect(&imagerect, (dtoolh - hws[4]) / 2, (dtoolh - hhs[4]) / 2);
  350.                     draw_clouds(imagerect.left, imagerect.top, 4, curcloudtype);
  351.                     sprintf(spbuf, "Cloudy (%d)", curcloudtype);
  352.                     toolname = spbuf;
  353.                 } else {
  354.                     toolname = "Clear";
  355.                 }
  356.             } else {
  357.                 toolname = "Clouds";
  358.                 enabled = FALSE;
  359.             }
  360.             break;
  361.         case windstool:
  362.             if (enabledtooltype[windstool]) {
  363.                 InsetRect(&imagerect, (dtoolh - hws[4]) / 2, (dtoolh - hhs[4]) / 2);
  364.                 draw_winds(imagerect.left, imagerect.top, 4, curwinddir, curwindforce);
  365.                 if (curwindforce > 0) {
  366.                     sprintf(spbuf, "Winds %s, %d", dirnames[curwinddir], curwindforce);
  367.                     toolname = spbuf;
  368.                 } else {
  369.                     toolname = "Calm";
  370.                 }
  371.             } else {
  372.                 toolname = "Winds";
  373.                 enabled = FALSE;
  374.             }
  375.             break;
  376. #if 0
  377.         case viewtool:
  378.             break;
  379. #endif
  380.         default:
  381.             /* ??? */
  382.             break;
  383.     }
  384.     TextSize(12);
  385.     /* Draw a (short) text string in the image area. */
  386.     if (strlen(imbuf) > 0) {
  387.         /* (should center) */
  388.         MoveTo(tmprect.left + (dtoolh - StringWidth(tmpstr)) / 2, tmprect.bottom - 5);
  389.         DrawText(imbuf, 0, strlen(imbuf));
  390.     }
  391.     if (toolname != NULL) {
  392.         MoveTo(tmprect.left + dtoolh, tmprect.top + (auxtoolname != NULL ? dtoolh / 4 + 4
  393.                                                            : dtoolh / 2 + 5));
  394.         DrawText(toolname, 0, strlen(toolname));
  395.     }
  396.     if (auxtoolname != NULL) {
  397.         MoveTo(tmprect.left + dtoolh, tmprect.top + (dtoolh * 3) / 4);
  398.         DrawText(auxtoolname, 0, strlen(auxtoolname));
  399.     }
  400.     if (!paintable) {
  401.         gray_out_rect(&tmprect);
  402.     }
  403.     if (!enabled) {
  404.         gray_out_rect(&tmprect);
  405.     }
  406.     /* Draw gray dividing lines. */
  407.     PenPat(QD(gray));
  408.     MoveTo(tmprect.right - 1, tmprect.top);  Line(0, dtoolh);
  409.     MoveTo(tmprect.left, tmprect.bottom - 1);  Line(dtoolw, 0);
  410.     PenNormal();
  411.     /* Highlight the currently selected tool with a heavy outline rect. */
  412.     if (tool == tooltype) {
  413.         tmprect.bottom -= 1;  tmprect.right -= 1;
  414.         InvertRect(&tmprect);
  415.         InsetRect(&tmprect, 3, 3);
  416.         InvertRect(&tmprect);
  417.         if (!enabledtooltype[tool]) {
  418.             InsetRect(&tmprect, -3, -3);
  419.             gray_out_rect(&tmprect);
  420.         }
  421.     }
  422. }
  423.  
  424. /* Respond to a mouse down in the designer's window. */
  425.  
  426. /* This macro implements cycling of a variable through a set of consecutive
  427.    values, with direction controlled by the shift key.  If the limit is 0,
  428.    then the cycling part is not done. */
  429.  
  430. #define OPTION_CYCLE(var, lo, hi, mods)  \
  431.   if ((hi) - (lo) > 0) {  \
  432.     (var) = (((var) + ((mods) & shiftKey ? -1 : 1) - (lo) + ((hi) - (lo))) % ((hi) - (lo))) + (lo);  \
  433.   } else {  \
  434.     (var) = ((var) + ((mods) & shiftKey ? -1 : 1));  \
  435.   }
  436.  
  437. do_mouse_down_design(mouse, mods)
  438. Point mouse;
  439. int mods;
  440. {
  441.     int oldtool, poppedtool, newutype, newbgttype, toolchoice;
  442.     Feature *feature;
  443.     Rect tmprect;
  444.     ControlHandle control;
  445.     long choice;
  446.     extern int nextfid;
  447.  
  448.     tmprect.left = 0;  tmprect.right = dtoolw;
  449.     oldtool = poppedtool = tooltype;
  450.     toolchoice = (mouse.v / dtoolh) + (mouse.h > dtoolw ? (numtooltypes / 2) : 0);
  451.     FindControl(mouse, designwin, &control);
  452.     if (control == ttypepopup) {
  453.         TrackControl(control, mouse, (void *) -1);
  454.         choice = LoWord(GetCtlValue(control));
  455.         if (choice > 0) curttype = choice - 1;
  456.         poppedtool = terraintool;
  457.     } else if (control == utypepopup) {
  458.         mark_allowed_unit_types();
  459.         TrackControl(control, mouse, (void *) -1);
  460.         choice = LoWord(GetCtlValue(control));
  461.         if (choice > 0) curutype = choice - 1;
  462.         poppedtool = unittool;
  463.     } else if (control == sidepopup) {
  464.         mark_allowed_sides();
  465.         TrackControl(control, mouse, (void *) -1);
  466.         choice = LoWord(GetCtlValue(control));
  467.         if (choice > 0) {
  468.             cursidenumber = choice;
  469.             if (cursidenumber > numsides) cursidenumber = 0;;
  470.         }
  471.         poppedtool = peopletool;
  472.     } else if (control == mtypepopup) {
  473.         TrackControl(control, mouse, (void *) -1);
  474.         choice = LoWord(GetCtlValue(control));
  475.         if (choice > 0) curmtype = choice - 1;
  476.         poppedtool = materialtool;
  477.     } else if (control == featurepopup) {
  478.         TrackControl(control, mouse, (void *) -1);
  479.         choice = LoWord(GetCtlValue(control));
  480.         if (choice > 0) {
  481.             curfid = choice - 1; /* not reliable */
  482.             curfeature = find_feature(curfid);
  483.         }
  484.         poppedtool = featuretool;
  485.     } else if (control == newfeaturebutton) {
  486.         sprintf(spbuf, "%d", nextfid);
  487.         if ((feature = create_feature("feature", copy_string(spbuf))) != NULL) {
  488.             curfeature = feature;
  489.             curfid = feature->id;
  490.             feature_rename_dialog(feature);
  491.             update_feature_menu(feature);
  492.         }
  493.         poppedtool = featuretool;
  494.     } else if (control == featurerenamebutton) {
  495.         feature_rename_dialog(curfeature);
  496.         poppedtool = featuretool;
  497.     } else if (enabledtooltype[toolchoice]) {
  498.         /* Any other click selects the tool. */
  499.         if (toolchoice != brushsizetool) tooltype = toolchoice;
  500.         /* Now handle any shortcuts. */
  501.         switch (toolchoice) {
  502.             case notool:
  503.                 break;
  504.             case terraintool:
  505.                 if (mods & optionKey) {
  506.                     /* Option-click and Option-Shift-click cycle through all
  507.                        the "foreground" terrain types. */
  508.                     OPTION_CYCLE(curttype, 0, numttypes, mods);
  509.                 } else if ((mods & cmdKey) && t_is_cell(curttype)) {
  510.                     /* Cmd-click and Cmd-Shift-click cycle through all
  511.                        the "background" terrain types. */
  512.                     newbgttype = curbgttype;
  513.                     do {
  514.                         OPTION_CYCLE(newbgttype, 0, numttypes, mods);
  515.                         if (newbgttype == curbgttype) break;
  516.                     } while (!t_is_cell(newbgttype));
  517.                     curbgttype = newbgttype;
  518.                 }
  519.                 break;
  520.             case unittool:
  521.                 if (mods & optionKey) {
  522.                     /* Option-click and Option-Shift-click cycle through all
  523.                        the types allowed for the current side. */
  524.                     newutype = curutype;
  525.                     do {
  526.                         OPTION_CYCLE(newutype, 0, numutypes, mods);
  527.                         if (newutype == curutype) break;
  528.                     } while (!type_allowed_on_side(newutype, side_n(cursidenumber)));
  529.                     curutype = newutype;
  530.                 }
  531.                 break;
  532.             case peopletool:
  533.                 if (mods & optionKey) {
  534.                     /* Option-click and Option-Shift-click cycle around all the sides. */
  535.                     OPTION_CYCLE(cursidenumber, 0, numsides + 1, mods);
  536.                 }
  537.                 break;
  538.             case featuretool:
  539.                 if (mods & optionKey && nextfid > 1) {
  540.                     /* Option-click and Option-Shift-click cycle around the features. */
  541.                     OPTION_CYCLE(curfid, 0, nextfid, mods);
  542.                     curfeature = find_feature(curfid);
  543.                 }
  544.                 break;
  545.             case brushsizetool:
  546.                 if (mods & optionKey) {
  547.                     /* Option-click and Option-Shift-click cycle through brush sizes. */
  548.                     OPTION_CYCLE(curbrushradius, 0, 99, mods);
  549.                 }
  550.                 break;
  551.             case materialtool:
  552.                 if (mods & optionKey) {
  553.                     /* Option-click and Option-Shift-click cycle around amounts. */
  554.                     OPTION_CYCLE(curmamount, 0, 99, mods);
  555.                 }
  556.                 break;
  557.             case elevationtool:
  558.                 if (mods & optionKey) {
  559.                     /* Option-click and Option-Shift-click adjust the elevation. */
  560.                     OPTION_CYCLE(curelevation, minelev, maxelev + 1, mods);
  561.                 }
  562.                 break;
  563.             case temperaturetool:
  564.                 if (mods & optionKey) {
  565.                     /* Option-click and Option-Shift-click adjust the temp. */
  566.                     OPTION_CYCLE(curtemperature, mintemp, maxtemp + 1, mods);
  567.                 }
  568.                 break;
  569.             case cloudstool:
  570.                 if (mods & optionKey) {
  571.                     /* Option-click and Option-Shift-click adjust the cloud type. */
  572.                     OPTION_CYCLE(curcloudtype, 0, 4, mods);
  573.                 }
  574.                 break;
  575.             case windstool:
  576.                 if (mods & optionKey) {
  577.                     /* Option-click and Option-Shift-click adjust the wind force. */
  578.                     OPTION_CYCLE(curwindforce, minwindforce, maxwindforce, mods);
  579.                 } else if (mods & cmdKey) {
  580.                     /* Cmd-click and Cmd-Shift-click adjust the direction. */
  581.                     OPTION_CYCLE(curwinddir, 0, NUMDIRS, mods);
  582.                 }
  583.                 break;
  584.             default:
  585.                 break;
  586.         }
  587.     }
  588.     /* Draw the old and new tools. */
  589.     if (oldtool != tooltype) {
  590.         draw_design_window_tool(oldtool);
  591.     }
  592.     if (poppedtool != tooltype) {
  593.         draw_design_window_tool(poppedtool);
  594.     }
  595.     draw_design_window_tool(tooltype);
  596.     if (toolchoice != tooltype) draw_design_window_tool(toolchoice);
  597.     /* As a special case, redraw the unit tool if the side tool was touched. */
  598.     if (tooltype == peopletool || poppedtool == peopletool) {
  599.         draw_design_window_tool(unittool);
  600.     }
  601.     /* (should only draw controls in relevant tools) */
  602.     DrawControls(designwin);
  603. }
  604.  
  605. mark_allowed_unit_types()
  606. {
  607.     Side *side = side_n(cursidenumber);
  608.     int u;
  609.  
  610.     for_all_unit_types(u) {
  611.         EnableItem(utypemenu, u + 1);
  612.         SetItemMark(utypemenu, u + 1,
  613.                     (type_allowed_on_side(u, side) ? diamondMark : noMark));
  614.     }
  615. }
  616.  
  617. mark_allowed_sides()
  618. {
  619.     Side *side;
  620.  
  621.     for_all_sides(side) {
  622.         EnableItem(sidemenu, side_number(side));
  623.         SetItemMark(sidemenu, side_number(side),
  624.                     (type_allowed_on_side(curutype, side) ? diamondMark : noMark));
  625.     }
  626.     EnableItem(sidemenu, numsides + 1);
  627.     SetItemMark(sidemenu, numsides + 1,
  628.                 (type_allowed_on_side(curutype, NULL) ? diamondMark : noMark));
  629. }
  630.  
  631. feature_rename_dialog(feature)
  632. Feature *feature;
  633. {
  634.     short done = FALSE, ditem;
  635.     char *newtypename, *newname;
  636.     Str255 tmpstr;
  637.     DialogPtr win;
  638.     short itemtype;  Handle itemhandle;  Rect itemrect;
  639.  
  640.     if (feature == NULL) return;
  641.     win = GetNewDialog(dFeatureRename, NULL, (DialogPtr) -1L);
  642.     /* Seed the text items with the original names. */
  643.     newtypename = feature->typename;
  644.     if (newtypename == NULL) newtypename = "";
  645.     GetDItem(win, diFeatureRenameType, &itemtype, &itemhandle, &itemrect);
  646.     c2p(newtypename, tmpstr);
  647.     SetIText(itemhandle, tmpstr);
  648.     newname = feature->name;
  649.     if (newname == NULL) newname = "";
  650.     GetDItem(win, diFeatureRenameName, &itemtype, &itemhandle, &itemrect);
  651.     c2p(newname, tmpstr);
  652.     SetIText(itemhandle, tmpstr);
  653.     ShowWindow(win);
  654.     while (!done) {
  655.         /* Deactivate the front window. */
  656.         activate_window(FrontWindow(), FALSE);
  657.         ModalDialog(NULL, &ditem);
  658.         switch (ditem) {
  659.             case diRenameOK:
  660.                 GetDItem(win, diFeatureRenameType, &itemtype, &itemhandle, &itemrect);
  661.                 set_feature_type_name(feature, get_string_from_item(itemhandle));
  662.                 GetDItem(win, diFeatureRenameName, &itemtype, &itemhandle, &itemrect);
  663.                 set_feature_name(feature, get_string_from_item(itemhandle));
  664.                 /* Fall into next case. */
  665.             case diRenameCancel:
  666.                 done = TRUE;
  667.                 break;
  668.         }
  669.     }
  670.     DisposDialog(win);
  671. }
  672.  
  673. /* Handling of mousedowns in the map when designing. */
  674.  
  675. apply_designer_tool(map, h, v, mods)
  676. Map *map;
  677. int h, v, mods;
  678. {
  679.     int x, y, dir;
  680.     int oldt, oldpeop, oldfid;
  681.     Unit *unit;
  682.  
  683.     nearest_boundary(map, h, v, &x, &y, &dir);
  684.     switch (tooltype) {
  685.         case terraintool:
  686.             /* Dispatch on terrain subtype. */
  687.             switch (t_subtype(curttype)) {
  688.                 case cellsubtype:
  689.                     /* Choose to paint fg or bg type, depending on what's already
  690.                        there. */
  691.                     oldt = terrain_at(x, y);
  692.                     painttype = (curttype == oldt ? curbgttype : curttype);
  693.                     paint_cell(dside, x, y, curbrushradius, painttype);
  694.                     paint_on_drag(map, h, v, mods);
  695.                     break;
  696.                 case bordersubtype:
  697.                     /* Toggle border on first mouse down. */
  698.                     paint_border(dside, x, y, dir, curttype, -1);
  699.                     /* Dragging then adds or removes, depending on toggle's result. */
  700.                     border_on_drag(map, h, v, mods, border_at(x, y, dir, curttype));
  701.                     break;
  702.                 case connectionsubtype:
  703.                     /* Toggle connection on first mouse down. */
  704.                     paint_connection(dside, x, y, dir, curttype, -1);
  705.                     /* Dragging then adds or removes, depending on toggle's result. */
  706.                     connect_on_drag(map, h, v, mods, connection_at(x, y, dir, curttype));
  707.                     break;
  708.                 case coatingsubtype:
  709.                     paint_coating(dside, x, y, curbrushradius, curttype, curdepth);
  710.                     paint_on_drag(map, h, v, mods);
  711.                     break;
  712.                 default:
  713.                     terrain_subtype_warning("apply tool", curttype);
  714.                     break;
  715.             }
  716.             return;
  717.         case unittool:
  718.             /* A last check, should never(?) fail. */
  719.             if (!type_allowed_on_side(curutype, side_n(cursidenumber))) {
  720.                 SysBeep(20);
  721.                 return;
  722.             }
  723.             if ((unit = designer_create_unit(dside, curutype, cursidenumber, x, y)) != NULL) {
  724.                 /* Make the new unit automatically be the current selection. */
  725.                 unselect_all(map);
  726.                 select_unit_on_map(map, unit);
  727.                 draw_selections_at(map, unit->x, unit->y);
  728.             } else {
  729.                 /* Beep if the creation failed for some reason. */
  730.                 SysBeep(20);
  731.             }
  732.             /* No use for drag painting here, unlike most other tools. */
  733.             break;
  734.         case peopletool:
  735.             /* Paint people or clear, inverting from what is already here. */
  736.             oldpeop = people_side_at(x, y);
  737.             paintpeop = (cursidenumber == oldpeop ? NOBODY : cursidenumber);
  738.             paint_people(dside, x, y, curbrushradius, paintpeop);
  739.             paint_on_drag(map, h, v, mods);
  740.             break;
  741.         case featuretool:
  742.             oldfid = raw_feature_at(x, y);
  743.             paintfid = (curfid == oldfid ? 0 : curfid);
  744.             paint_feature(dside, x, y, curbrushradius, paintfid);
  745.             paint_on_drag(map, h, v, mods);
  746.             break;
  747.         case materialtool:
  748.             paint_material(dside, x, y, curbrushradius, curmtype, curmamount);
  749.             paint_on_drag(map, h, v, mods);
  750.             break;
  751.         case elevationtool:
  752.             paint_elevation(dside, x, y, curbrushradius, curelevation);
  753.             paint_on_drag(map, h, v, mods);
  754.             break;
  755.         case temperaturetool:
  756.             paint_temperature(dside, x, y, curbrushradius, curtemperature);
  757.             paint_on_drag(map, h, v, mods);
  758.             break;
  759.         case cloudstool:
  760.             paint_clouds(dside, x, y, curbrushradius, curcloudtype, curcloudbottom, curcloudheight);
  761.             paint_on_drag(map, h, v, mods);
  762.             break;
  763.         case windstool:
  764.             paint_winds(dside, x, y, curbrushradius, curwinddir, curwindforce);
  765.             paint_on_drag(map, h, v, mods);
  766.             break;
  767.         default:
  768.             SysBeep(20);
  769.     }
  770. }
  771.  
  772. paint_on_drag(map, h0, v0, mods)
  773. Map *map;
  774. int h0, v0, mods;
  775. {
  776.     Point pt0, pt1, newmouse;
  777.     int h1, v1, drawn = FALSE, x, y;
  778.     Rect tmprect;
  779.  
  780.     SetPt(&pt0, h0, v0);
  781.     SetPt(&pt1, h0, v0);
  782.     SetRect(&tmprect, h0, v0, h0, v0);
  783.     while (WaitMouseUp()) {
  784.         GetMouse(&newmouse);
  785.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  786.             pt1 = newmouse;
  787.             nearest_cell(map, pt1.h, pt1.v, &x, &y);
  788.             if (in_area(x, y)) {
  789.                 switch (tooltype) {
  790.                     case terraintool:
  791.                         /* Dispatch on terrain subtype. */
  792.                         switch (t_subtype(curttype)) {
  793.                             /* This sort of drag-paint only works for area fillers,
  794.                                bords/conns use different algorithm. */
  795.                             case cellsubtype:
  796.                                 paint_cell(dside, x, y, curbrushradius, painttype);
  797.                                 break;
  798.                             case coatingsubtype:
  799.                                 paint_coating(dside, x, y, curbrushradius, curttype, curdepth);
  800.                                 break;
  801.                         }
  802.                         break;
  803.                     case peopletool:
  804.                         paint_people(dside, x, y, curbrushradius, paintpeop);
  805.                         break;
  806.                     case materialtool:
  807.                         paint_material(dside, x, y, curbrushradius, curmtype, curmamount);
  808.                         break;
  809.                     case featuretool:
  810.                         paint_feature(dside, x, y, curbrushradius, paintfid);
  811.                         break;
  812.                     case elevationtool:
  813.                         paint_elevation(dside, x, y, curbrushradius, curelevation);
  814.                         break;
  815.                     case temperaturetool:
  816.                         paint_temperature(dside, x, y, curbrushradius, curtemperature);
  817.                         break;
  818.                     case cloudstool:
  819.                         paint_clouds(dside, x, y, curbrushradius, curcloudtype, curcloudbottom, curcloudheight);
  820.                         break;
  821.                     case windstool:
  822.                         paint_winds(dside, x, y, curbrushradius, curwinddir, curwindforce);
  823.                         break;
  824.                 }
  825.             }
  826.         }
  827.     }
  828. }
  829.  
  830. border_on_drag(map, h0, v0, mods, paintmode)
  831. Map *map;
  832. int h0, v0, mods, paintmode;
  833. {
  834.     Point pt0, pt1, newmouse;
  835.     int h1, v1, drawn = FALSE, x, y, dir;
  836.     Rect tmprect;
  837.  
  838.     SetPt(&pt0, h0, v0);
  839.     SetPt(&pt1, h0, v0);
  840.     SetRect(&tmprect, h0, v0, h0, v0);
  841.     while (WaitMouseUp()) {
  842.         GetMouse(&newmouse);
  843.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  844.             pt1 = newmouse;
  845.             nearest_boundary(map, pt1.h, pt1.v, &x, &y, &dir);
  846.             if (inside_area(x, y)) {
  847.                 paint_border(dside, x, y, dir, curttype, paintmode);
  848.             }
  849.         }
  850.     }
  851. }
  852.  
  853. connect_on_drag(map, h0, v0, mods, paintmode)
  854. Map *map;
  855. int h0, v0, mods, paintmode;
  856. {
  857.     Point pt0, pt1, newmouse;
  858.     int h1, v1, drawn = FALSE, x, y, dir;
  859.     Rect tmprect;
  860.  
  861.     SetPt(&pt0, h0, v0);
  862.     SetPt(&pt1, h0, v0);
  863.     SetRect(&tmprect, h0, v0, h0, v0);
  864.     while (WaitMouseUp()) {
  865.         GetMouse(&newmouse);
  866.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  867.             pt1 = newmouse;
  868.             nearest_boundary(map, pt1.h, pt1.v, &x, &y, &dir);
  869.             if (inside_area(x, y)) {
  870.                 paint_connection(dside, x, y, dir, curttype, paintmode);
  871.             }
  872.         }
  873.     }
  874. }
  875.  
  876. #define set_flag_from_ditem(di,place)  \
  877.   GetDItem(win, (di), &itemtype, &itemhandle, &itemrect);  \
  878.   (place) = GetCtlValue((ControlHandle) itemhandle); 
  879.  
  880. #define put_number_into_ditem(di,num)  \
  881.   GetDItem(win, (di), &itemtype, &itemhandle, &itemrect);  \
  882.   NumToString((num), tmpstr);  \
  883.   SetIText(itemhandle, tmpstr);
  884.  
  885. #define get_number_from_ditem(di,place)  \
  886.   GetDItem(win, (di), &itemtype, &itemhandle, &itemrect);  \
  887.   GetIText(itemhandle, tmpstr);  \
  888.   StringToNum(tmpstr, &(place));
  889.  
  890. #define get_string_from_ditem(di,buf)  \
  891.   GetDItem(win, (di), &itemtype, &itemhandle, &itemrect);  \
  892.   GetIText(itemhandle, tmpstr);  \
  893.   strncpy((buf), tmpstr+1, tmpstr[0]); /* this is basically p2c */  \
  894.   (buf)[tmpstr[0]] = '\0';
  895.  
  896. /* This allows the designer to choose which parts of a game to write out. */
  897.  
  898. int defunitids; /* should be module slot */
  899.  
  900. designer_save_dialog()
  901. {
  902.     int done = FALSE;
  903.     short ditem;
  904.     char namebuf[BUFSIZE];
  905.     Str255 tmpstr;
  906.     Point pnt;
  907.     WindowPtr win;
  908.     Module *module;
  909.     SFReply reply;
  910.     short itemtype;  Handle itemhandle;  Rect itemrect;
  911.     
  912.     win = GetNewDialog(dDesignerSave, NULL, (DialogPtr) -1L);
  913.     module = create_game_module(NULL);
  914.     module->title = "Designer-saved data";
  915.     if (module == NULL) { SysBeep(20); return; }
  916.     init_module_reshape(module);
  917.     /* Only rarely does the designer not want to compress all the area layers. */
  918.     module->compresslayers = TRUE;
  919.     GetDItem(win, diDesignerSaveCompress, &itemtype, &itemhandle, &itemrect);
  920.     SetCtlValue((ControlHandle) itemhandle, module->compresslayers);
  921.     while (!done) {
  922.         /* Deactivate the front window. */
  923.         activate_window(FrontWindow(), FALSE);
  924.         ModalDialog(NULL, &ditem);
  925.         switch (ditem) {
  926.             case diDesignerSaveOK:
  927.                 get_string_from_ditem(diDesignerSaveName, namebuf);
  928.                 module->name = copy_string(namebuf);
  929.                 set_flag_from_ditem(diDesignerSaveTypes, module->deftypes);
  930.                 set_flag_from_ditem(diDesignerSaveTables, module->deftables);
  931.                 set_flag_from_ditem(diDesignerSaveGlobals, module->defglobals);
  932.                 set_flag_from_ditem(diDesignerSaveWorld, module->defworld);
  933.                 set_flag_from_ditem(diDesignerSaveAreas, module->defareas);
  934.                 set_flag_from_ditem(diDesignerSaveAreaTerrain, module->defareaterrain);
  935.                 set_flag_from_ditem(diDesignerSaveAreaMisc, module->defareamisc);
  936.                 set_flag_from_ditem(diDesignerSaveAreaWeather, module->defareaweather);
  937.                 set_flag_from_ditem(diDesignerSaveAreaMaterial, module->defareamaterial);
  938.                 set_flag_from_ditem(diDesignerSaveSides, module->defsides);
  939.                 set_flag_from_ditem(diDesignerSaveSideViews, module->defsideviews);
  940.                 set_flag_from_ditem(diDesignerSavePlayers, module->defplayers);
  941.                 set_flag_from_ditem(diDesignerSaveUnits, module->defunits);
  942.                 set_flag_from_ditem(diDesignerSaveUnitIds, defunitids);
  943.                 set_flag_from_ditem(diDesignerSaveUnitProps, module->defunitprops);
  944.                 set_flag_from_ditem(diDesignerSaveUnitMoves, module->defunitacts);
  945.                 set_flag_from_ditem(diDesignerSaveUnitPlans, module->defunitplans);
  946.                 set_flag_from_ditem(diDesignerSaveScoring, module->defscoring);
  947.                 set_flag_from_ditem(diDesignerSaveHistory, module->defhistory);
  948.                 set_flag_from_ditem(diDesignerSaveCompress, module->compresslayers);
  949.                 /* Collect the file and path to save to. */
  950.                 SetPt(&pnt, 100, 100);
  951.                 sprintf(spbuf, "%s.g", namebuf);
  952.                 c2p(spbuf, tmpstr);
  953.                 SFPutFile(pnt, "\p", tmpstr, (DialogPtr) nil, &reply);
  954.                 if (reply.good) {
  955.                     /* Make the location of the file be the current volume. */
  956.                     SetVol(reply.fName, reply.vRefNum);
  957.                     p2c(((char *) reply.fName), namebuf);
  958.                     module->filename = copy_string(namebuf);
  959.                     if (!write_game_module(module)) {
  960.                         run_warning("Couldn't write the module \"%s\"!", module->filename);
  961.                         /* Don't fall through, might be able to fix by changing save options. */
  962.                         break;
  963.                     }
  964.                 } else {
  965.                     break;
  966.                 }
  967.                 /* Fall through to next case. */
  968.             case diDesignerSaveCancel:
  969.                 done = TRUE;
  970.                 break;
  971.             case diDesignerSaveTypes:
  972.             case diDesignerSaveTables:
  973.             case diDesignerSaveGlobals:
  974.             case diDesignerSaveWorld:
  975.             case diDesignerSaveAreas:
  976.             case diDesignerSaveAreaTerrain:
  977.             case diDesignerSaveAreaMisc:
  978.             case diDesignerSaveAreaWeather:
  979.             case diDesignerSaveAreaMaterial:
  980.             case diDesignerSaveSides:
  981.             case diDesignerSaveSideNames:
  982.             case diDesignerSaveSideProps:
  983.             case diDesignerSaveSideViews:
  984.             case diDesignerSavePlayers:
  985.             case diDesignerSaveUnits:
  986.             case diDesignerSaveUnitIds:
  987.             case diDesignerSaveUnitProps:
  988.             case diDesignerSaveUnitMoves:
  989.             case diDesignerSaveUnitPlans:
  990.             case diDesignerSaveScoring:
  991.             case diDesignerSaveHistory:
  992.             case diDesignerSaveCompress:
  993.                 /* Toggle check boxes. */
  994.                 GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
  995.                 SetCtlValue((ControlHandle) itemhandle,
  996.                             !GetCtlValue((ControlHandle) itemhandle));
  997.                 break;
  998.             case diDesignerSaveModule:
  999.                 /* (should bring up a dialog to set module properties) */
  1000.                 break;
  1001.             case diDesignerSaveReshape:
  1002.                 /* Bring up *another* modal dialog. */
  1003.                 designer_reshape_dialog(module);
  1004.                 break;
  1005.         }
  1006.     }
  1007.     DisposDialog(win);
  1008. }
  1009.  
  1010. /* A special dialog that allows for saving a world of different dimensions than is
  1011.    currently being used in the game. */
  1012.  
  1013. designer_reshape_dialog(module)
  1014. Module *module;
  1015. {
  1016.     int done = FALSE;
  1017.     short ditem;
  1018.     WindowPtr win;
  1019.     Str255 tmpstr;
  1020.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1021.     
  1022.     win = GetNewDialog(dDesignerReshape, NULL, (DialogPtr) -1L);
  1023.     while (!done) {
  1024.         /* Deactivate the front window. */
  1025.         activate_window(FrontWindow(), FALSE);
  1026.           put_number_into_ditem(diDesignerReshapeOrigWidth, area.width);
  1027.           put_number_into_ditem(diDesignerReshapeOrigHeight, area.height);
  1028.           put_number_into_ditem(diDesignerReshapeOrigWorld, world.circumference);
  1029.           put_number_into_ditem(diDesignerReshapeOrigSubWidth, module->subareawidth);
  1030.           put_number_into_ditem(diDesignerReshapeOrigSubHeight, module->subareaheight);
  1031.           put_number_into_ditem(diDesignerReshapeOrigSubX, module->subareax);
  1032.           put_number_into_ditem(diDesignerReshapeOrigSubY, module->subareay);
  1033.           put_number_into_ditem(diDesignerReshapeOutputSubWidth, module->finalsubareawidth);
  1034.           put_number_into_ditem(diDesignerReshapeOutputSubHeight, module->finalsubareaheight);
  1035.           put_number_into_ditem(diDesignerReshapeOutputSubX, module->finalsubareax);
  1036.           put_number_into_ditem(diDesignerReshapeOutputSubY, module->finalsubareay);
  1037.           put_number_into_ditem(diDesignerReshapeOutputWidth, module->finalwidth);
  1038.           put_number_into_ditem(diDesignerReshapeOutputHeight, module->finalheight);
  1039.           put_number_into_ditem(diDesignerReshapeOutputWorld, module->finalcircumference);
  1040. /*          put_number_into_ditem(diDesignerReshapeFillTerrain, module->fillterrain); */
  1041.         ModalDialog(NULL, &ditem);
  1042.         switch (ditem) {
  1043.             case diDesignerReshapeOK:
  1044.                   get_number_from_ditem(diDesignerReshapeOrigSubWidth, module->subareawidth);
  1045.                   get_number_from_ditem(diDesignerReshapeOrigSubHeight, module->subareaheight);
  1046.                   get_number_from_ditem(diDesignerReshapeOrigSubX, module->subareax);
  1047.                   get_number_from_ditem(diDesignerReshapeOrigSubY, module->subareay);
  1048.                   get_number_from_ditem(diDesignerReshapeOutputSubWidth, module->finalsubareawidth);
  1049.                   get_number_from_ditem(diDesignerReshapeOutputSubHeight, module->finalsubareaheight);
  1050.                   get_number_from_ditem(diDesignerReshapeOutputSubX, module->finalsubareax);
  1051.                   get_number_from_ditem(diDesignerReshapeOutputSubY, module->finalsubareay);
  1052.                   get_number_from_ditem(diDesignerReshapeOutputWidth, module->finalwidth);
  1053.                   get_number_from_ditem(diDesignerReshapeOutputHeight, module->finalheight);
  1054.                   get_number_from_ditem(diDesignerReshapeOutputWorld, module->finalcircumference);
  1055. /*                  get_number_from_ditem(diDesignerReshapeFillTerrain, module->fillterrain);  */
  1056.                 /* Fall through to next case. */
  1057.             case diDesignerReshapeCancel:
  1058.                 done = TRUE;
  1059.                 break;
  1060.         }
  1061.     }
  1062.     DisposDialog(win);
  1063. }
  1064.  
  1065. #endif /* DESIGNERS */
  1066.